package com.lc.projects.unit.thread.part05.test1;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;

//合并任务的结果
public class Test3 {
	public static void main(String[] args) {
		DocumentMock mock = new DocumentMock();
		String[][] documents = mock.generateDocument(100, 1000, "hello");
		ForkJoinPool pool = new ForkJoinPool();
		DocumentTask task = new DocumentTask(documents, 0, 100, "hello");
		pool.execute(task);

		do {
			System.out.println("***************************");

			System.out.println("Main:Thread Count:" + pool.getActiveThreadCount());
			System.out.println("Main:Thread Steal:" + pool.getStealCount());
			System.out.println("Main: Parallelism:" + pool.getParallelism());
			System.out.println("Main: Task Queued:" + pool.getQueuedTaskCount());
			
			System.out.println("***************************");
			
			
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} while (!task.isDone());

		pool.shutdown();

		try {
			pool.awaitTermination(1, TimeUnit.HOURS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		try {
			System.out.println("Main: The word appears " + task.get());
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}

	}
}

class DocumentMock {
	private String[] words = { "the", "hello", "goodbye", "packet", "java", "thred", "pool", "random", "class",
			"main" };

	public String[][] generateDocument(int numLines, int numWords, String word) {
		int counter = 0;
		String[][] document = new String[numLines][numWords];
		Random random = new Random();
		for (int i = 0; i < numLines; i++) {
			for (int j = 0; j < numWords; j++) {
				int index = random.nextInt(words.length);
				document[i][j] = words[index];
				if (document[i][j].equals(word)) {
					counter++;
				}
			}
		}
		System.out.println("Document Mock: The word " + word + " appears " + counter);
		return document;
	}
}

class DocumentTask extends RecursiveTask<Integer> {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String[][] documents;
	private int start, end;
	private String word;

	public DocumentTask(String[][] documents, int start, int end, String word) {
		super();
		this.documents = documents;
		this.start = start;
		this.end = end;
		this.word = word;
	}

	@Override
	protected Integer compute() {
		int result = 0;
		if (end - start < 10) {
			result = search(documents, start, end, word);
		} else {
			int middle = (start + end) / 2;
			DocumentTask d1 = new DocumentTask(documents, start, middle, word);
			DocumentTask d2 = new DocumentTask(documents, middle, end, word);
			invokeAll(d1, d2);
			try {
				result = d1.get() + d2.get();
			} catch (InterruptedException | ExecutionException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	private Integer search(String[][] document, int start, int end, String word) {
		List<LineTask> tasks = new ArrayList<>();
		for (int i = start; i < end; i++) {
			LineTask lineTask = new LineTask(document[i], 0, document[i].length, word);
			tasks.add(lineTask);
		}
		invokeAll(tasks);

		Integer result = 0;
		for (int i = 0; i < tasks.size(); i++) {
			LineTask task = tasks.get(i);
			try {
				result = result + task.get();
			} catch (InterruptedException | ExecutionException e) {
				e.printStackTrace();
			}
		}

		return new Integer(result);
	}
}

class LineTask extends RecursiveTask<Integer> {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String[] lines;
	private int start;
	private int end;
	private String word;

	public LineTask(String[] lines, int start, int end, String word) {
		super();
		this.lines = lines;
		this.start = start;
		this.end = end;
		this.word = word;
	}

	@Override
	protected Integer compute() {
		Integer result = null;
		if (end - start < 100) {
			result = searchLine(lines, start, end, word);
		} else {
			int middle = (start + end) / 2;
			LineTask l1 = new LineTask(lines, start, middle, word);
			LineTask l2 = new LineTask(lines, middle, end, word);
			invokeAll(l1, l2);
			try {
				result = l1.get() + l2.get();
			} catch (InterruptedException | ExecutionException e) {
				e.printStackTrace();
			}

		}
		return result;
	}

	private Integer searchLine(String[] lines, int start, int end, String word) {
		int counter = 0;
		for (int i = start; i < end; i++) {
			if (lines[i].equals(word)) {
				counter++;
			}
		}

		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		return counter;
	}
}
